﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace 下位机程序
{
    public partial class Form1 : Form
    {
        private bool success = false;
        private int count = 0;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            serialPort1.PortName = "COM1";
            try
            {
                serialPort1.Open();
                label2.Text = "串口已打开";
                success = true;
                //启动定时器
                timer1.Start();
            }
            catch
            {
                label2.Text = "串口未打开";
            }
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            //生成数据
            float fs = 1000;
            float k = 380f / 2048f;
            float bias = 2048 * k;
            int N = 200;
            ushort[] sample = new ushort[N];
            Random rd=new Random();
            float angle0 = Convert.ToSingle(rd.Next(100) / 100.0 * 2 * Math.PI);
            for (int i = 0; i < N; i++)
            {
                float t = i / fs;
                float Ui = Convert.ToSingle(220 * Math.Sqrt(2) * Math.Sin(t * 50 * 2 * Math.PI + angle0));
                sample[i] = Convert.ToUInt16((Ui + bias) / k);
            }
            
            //合成数据帧
            byte[] buffer = new byte[1 + 4 * 3 + 4 + 2 * N + 2 + 1];
            buffer[0] = 0x66;
            Array.Copy(BitConverter.GetBytes(fs),0, buffer,1, 4);
            Array.Copy(BitConverter.GetBytes(k), 0, buffer, 1+4, 4);
            Array.Copy(BitConverter.GetBytes(bias), 0, buffer, 1+4*2, 4);
            Array.Copy(BitConverter.GetBytes(N), 0, buffer, 1+4*3, 4);
            for (int i = 0; i < N; i++)
            {
                Array.Copy(BitConverter.GetBytes(sample[i]), 0, buffer, 1 + 4 * 3 + 4 + 2*i, 2);
            }
            byte[] crc16 = CRC16(buffer,1,buffer.Length-3);//从采样频率到采样数组所有byte的CRC16
            buffer[1 + 4 * 3 + 4 + 2 * N] = crc16[0];
            buffer[1 + 4 * 3 + 4 + 2 * N + 1] = crc16[1];
            buffer[1 + 4 * 3 + 4 + 2 * N + 2] = 0x66;

            //计数值更新，按照0,1,2,3,4循环变化
            count++;
            if (count >= 5)
                count = 0;
            //以五分之一的概率，对采样值加噪声
            if (count==0)
            {
                int i = rd.Next(N);
                buffer[1 + 4 * 3 + 4 + 2 * i+1] =0;
            }

            //发送数据帧
            serialPort1.Write(buffer, 0, buffer.Length);

        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (success==true)
                serialPort1.Close();
        }


        /// <summary>
        /// CRC16
        /// </summary>
        /// <param name="data">要进行计算的数组</param>
        /// <returns>计算后的数组</returns>
        /// begin：可以是0, 1, 2,
        /// end：最大为数组的长度
        private static byte[] CRC16(byte[] data, int begin, int end)
        {
            byte[] returnVal = new byte[2];
            byte CRC16Lo, CRC16Hi, CL, CH, SaveHi, SaveLo;
            int i, Flag;
            CRC16Lo = 0xFF;
            CRC16Hi = 0xFF;
            CL = 0x86;
            CH = 0x68;
            for (i = begin; i < end; i++)
            {
                CRC16Lo = (byte)(CRC16Lo ^ data[i]);//每一个数据与CRC寄存器进行异或
                for (Flag = 0; Flag <= 7; Flag++)
                {
                    SaveHi = CRC16Hi;
                    SaveLo = CRC16Lo;
                    CRC16Hi = (byte)(CRC16Hi >> 1);//高位右移一位
                    CRC16Lo = (byte)(CRC16Lo >> 1);//低位右移一位
                    if ((SaveHi & 0x01) == 0x01)//如果高位字节最后一位为
                    {
                        CRC16Lo = (byte)(CRC16Lo | 0x80);//则低位字节右移后前面补 否则自动补0
                    }
                    if ((SaveLo & 0x01) == 0x01)//如果LSB为1，则与多项式码进行异或
                    {
                        CRC16Hi = (byte)(CRC16Hi ^ CH);
                        CRC16Lo = (byte)(CRC16Lo ^ CL);
                    }
                }
            }
            returnVal[0] = CRC16Hi;//CRC高位
            returnVal[1] = CRC16Lo;//CRC低位
            return returnVal;
        }

    }
}